package cn.ac.iie.di.download;

import cn.ac.iie.di.global.GlobalParas;
import static cn.ac.iie.di.global.GlobalParas.REDIS_TIME;
import static cn.ac.iie.di.global.GlobalParas.REDIS_UTIL;
import cn.ac.iie.di.tools.FileTools;
import cn.ac.iie.di.tools.GenerateMD5;
import cn.ac.iie.di.tools.TimeFormat;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;
import static org.apache.commons.io.FileUtils.copyInputStreamToFile;
import org.redisson.RedissonClient;

/**
 *
 * @author YG
 */
public class DownLoadFile implements Runnable {

    public static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(DownLoadFile.class.getName());
//    public static org.apache.log4j.Logger errRecord = org.apache.log4j.Logger.getLogger("errRecord");
    public ArrayBlockingQueue<String> recordPool = null;
    public ArrayBlockingQueue<String> tarPool = null;
    private boolean isQuit = false;
    private String dataType = "";

    public DownLoadFile(ArrayBlockingQueue<String> recordPool, ArrayBlockingQueue<String> tarPool, String dataType) {
        this.recordPool = recordPool;
        this.tarPool = tarPool;
        this.dataType = dataType;
    }

//    public void setIsQuit(boolean isQuit) {
//        this.isQuit = isQuit;
//    }
    @Override
    public void run() {
        long pathSize = 0l;
//        String fileTime = System.currentTimeMillis() + "";
        String dirName = GlobalParas.TAR_PATH + File.separator + System.currentTimeMillis() + "_t" + dataType;
        File f = new File(dirName);
        if (!f.getParentFile().exists()) {
            f.getParentFile().mkdirs();
        }
        String fileName = dirName + File.separator + System.currentTimeMillis() + "_t" + dataType + ".log";
        try {
            FileTools.creatTxtFile(fileName);
        } catch (IOException ex) {
            logger.error(ex, ex);
        }
        long time = System.currentTimeMillis() / 1000;
        int line = 0;
        BufferedWriter out = null;
        while (true) {
            try {
                String json = this.recordPool.poll();
                if (null != json) {
                    JSONObject object;
                    try {
                        object = JSONObject.fromObject(json);
                    } catch (Exception e) {
                        logger.error("The json is not completed, and the json :", e);
                        logger.error("The json read message is : " + json);
                        continue;
                    }
                    if (object != null) {
                        String type = object.getString("msg_type");
                        String[] allColumms = GlobalParas.TYPE_COLUMN.get(type);
                        if (null == allColumms || allColumms.length == 0) {
                            continue;
                        }
                        String[] urls = null;
                        String[] files = null;
                        for (String column : allColumms) {
                            switch (column.split("\\:")[2]) {
                                case "o":
                                    urls = new String[]{object.getString(column.split("\\:")[0])};
                                    files = new String[]{object.getString(column.split("\\:")[1])};
                                    break;
                                case "m":
                                    urls = getStrings(object, column.split("\\:")[0]);
                                    files = getStrings(object, column.split("\\:")[1]);
                                    break;
                            }
                            if (null == urls || null == files) {
                                continue;
                            }
                            if (urls.length == files.length && urls.length != 0 && files.length != 0) {

                                List<String> succUrl = new ArrayList<String>();
                                List<String> badUrl = new ArrayList<String>();
                                List<String> repUrl = new ArrayList<String>();
                                List<File> urlFiles = downFile(urls, files, succUrl, badUrl, repUrl, dirName);
                                int pic = 0;
                                int mp3 = 0;
                                int mp4 = 0;
                                int apk = 0;
                                int other = 0;
                                for (File size : urlFiles) {
                                    String[] suffix = size.getName().split("\\.");
                                    pathSize = pathSize + size.length();
                                    switch (suffix[suffix.length - 1]) {
                                        case "jpg":
                                            pic++;
                                            break;
                                        case "mp3":
                                            mp3++;
                                            break;
                                        case "mp4":
                                            mp4++;
                                            break;
                                        case "apk":
                                            apk++;
                                            break;
                                        default:
                                            other++;
                                            break;

                                    }
                                }
                                if (pic != 0 || mp3 != 0 || mp4 != 0 || apk != 0 || other != 0) {
                                    logger.info(type + " down success num is " + urlFiles.size() + " pic: " + pic + " mp3: " + mp3 + " mp4: " + mp4 + " apk: " + apk + " other: " + other);
                                }
                                for (String badPath : badUrl) {
                                    logger.error(badPath);
                                    logger.error(json);
                                }
                            } else {
                                logger.error("wrong record " + json);
                            }
                        }
                        line++;
                        try {
                            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName, true)));
                            out.write(json + "\r\n");
                            out.flush();
                        } catch (Exception e) {
                            logger.error(e, e);
                        } finally {
                            try {
                                if (out != null) {
                                    out.close();
                                }
                            } catch (IOException e) {
                                logger.error(e, e);
                            }
                        }
                    }
                }
//                else {
//                    logger.info("GlobalParas.JSON_STR_QUEUE is isEmpty");
//                    Thread.sleep(3000);
//                }

            } catch (Exception ex) {
                logger.error(ex, ex);
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                } catch (IOException e) {
                    logger.error(e, e);
                }
            }
            if ((pathSize >= GlobalParas.TAR_SIZE)
                    || (System.currentTimeMillis() / 1000 - time >= GlobalParas.TAR_TIMEOUT && pathSize > 0 && line > 0)
                    || line >= GlobalParas.TAR_MAXLINE
                    || GlobalParas.DWD_FLAG) {
                logger.info(dirName + " dir success");
                try {
                    this.tarPool.put(dirName);
                    logger.debug(dirName + ":" + fileName + ":" + pathSize + ":" + line);
                } catch (Exception ex) {
                    logger.error(ex);
                }
                if(GlobalParas.DWD_FLAG){
                    break;
                }
//                fileTime = System.currentTimeMillis() + "";
                dirName = GlobalParas.TAR_PATH + File.separator + System.currentTimeMillis() + "_t" + dataType;
                File dir = new File(dirName);
                logger.debug(dirName);
                if (!dir.getParentFile().exists()) {
                    boolean mkdType = dir.getParentFile().mkdirs();
                    if (!mkdType) {
                        logger.error("mkdir " + dir.getPath() + " fail");
                    } else {
                        logger.debug("mkdir " + dir.getPath() + " success");
                    }
                }
                time = System.currentTimeMillis() / 1000;
                pathSize = 0;
                line = 0;
                fileName = dirName + File.separator + System.currentTimeMillis() + "_t" + dataType + ".log";
                logger.debug(fileName);
                try {
                    FileTools.creatTxtFile(fileName);
                } catch (IOException ex) {
                    logger.error(ex, ex);
                }
            }
            if (this.isQuit && this.recordPool.isEmpty()) {
                break;
            }
        }
    }

    private static String[] getStrings(JSONObject object, String name) {
        String[] list = null;
        String urlStr = object.getString(name);
        list = urlStr.substring(1, urlStr.length() - 1).split(",");
        return list;
    }

    private static List<File> downFile(String[] picture_urls, String[] picture_files, List<String> succUrl, List<String> badUrl, List<String> repUrl, String filePa) {
//        logger.info("filePa-->" + filePa);
        List<File> succFile = new ArrayList<File>();
        for (int k = 0; k < picture_urls.length; k++) {
            String url = picture_urls[k].trim();
            if (url.trim().isEmpty()) {
                continue;
            }
            String path = picture_files[k].trim();
            logger.debug("download " + url + "  to " + path);
            try {
                GlobalParas.redissonUtils.tryLock(GlobalParas.redissonClient, GenerateMD5.string2MD5(url));
                if (!GlobalParas.REDIS_UTIL.exists(GenerateMD5.string2MD5(url))) {
                    String filePath = filePa + File.separator + path;
                    File f = new File(filePath);
                    if (!f.getParentFile().exists()) {
                        f.getParentFile().mkdirs();
                    }
                    URL httpUrl;
                    try {
                        httpUrl = new URL(url);
                    } catch (Exception ex) {
                        logger.error("url is not correct " + url + ex.getMessage(), ex);
//                    logger.error("url is not correct " + url);
                        badUrl.add(url);
                        continue;
                    }
                    int numTry = 0;
                    while (true) {
                        try {
//                            if (path.contains("apk")) {
//                                logger.info("this 11111111111111111 " + path);
//                            }
                            URLConnection connection = httpUrl.openConnection();
                            if (GlobalParas.RMFERER != null && !GlobalParas.RMFERER.isEmpty() && !GlobalParas.RMFERER.equalsIgnoreCase("null")) {
                                connection.addRequestProperty("referer", GlobalParas.RMFERER);
                            }
                            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
                            connection.setConnectTimeout(GlobalParas.MAX_CON_TIMELIMIT);
                            connection.setReadTimeout(GlobalParas.MAX_READ_TIMELIMIT);
                            copyInputStreamToFile(connection.getInputStream(), f);
                            GlobalParas.REDIS_UTIL.setex(GenerateMD5.string2MD5(url), path, GlobalParas.REDIS_TIME);
                            logger.debug("download success " + f);
                            succUrl.add(url);
                            succFile.add(f);
                            break;
                        } catch (Exception e) {
                            try {
                                //                       
                                FileUtils.copyURLToFile(httpUrl, f, GlobalParas.MAX_CON_TIMELIMIT, GlobalParas.MAX_READ_TIMELIMIT);
                                logger.debug("download success " + f);
                                succUrl.add(url);
                                succFile.add(f);
                                GlobalParas.REDIS_UTIL.setex(GenerateMD5.string2MD5(url), path, GlobalParas.REDIS_TIME);
                                break;
                            } catch (Exception ex) {
                                numTry++;
                                try {
                                    Thread.sleep(3000);
                                } catch (Exception x) {
                                }
                                if (numTry > GlobalParas.MAX_TRY) {
                                    logger.error(ex.getMessage(), ex);
                                    logger.error("download file " + httpUrl + "  to " + f.getAbsolutePath() + " failed!");
                                    badUrl.add(url);
                                    break;
                                }
                            }
                        }

                    }
                } else {
                    logger.debug("the url cantans: " + url);
                }
            } catch (InterruptedException ex) {
                logger.error(ex, ex);
            } finally {
                try {
                    GlobalParas.redissonUtils.unlock(GlobalParas.redissonClient, GenerateMD5.string2MD5(url));
                } catch (Exception ex) {
                    logger.error(ex, ex);
                }
            }
        }
        return succFile;
    }

}
